package com.goodcol.plugin.tool;

import com.intellij.openapi.application.PathManager;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.Cipher;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 版权License控制类
 *
 * @author 单红宇
 * @date 2024/3/8 16:16
 */
public class LicenseUtils {

    /**
     * LICENSE_DIR
     */
    private static final String LICENSE_DIR = ".idea";

    /**
     * LICENSE_FILE
     */
    private static final String LICENSE_FILE = "muses-quick-code.lic";

    /**
     * RSA-私钥
     */
    private static final String PRIVATE_KEY = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDVDBT1BxQv1SrqjAbS62oV2swa3RVbs4M8S4xIKgG" +
            "/ehwYq1q7GrYUxwrIebsbNAA592F76EhskiaiM/vRBzWZF2uLkWCuytfwBhANYpY2ltdtVdy0i3bEfePu9IiMsHtKMSOKrRviB3/pPT1VZnyvPO0BeUVtdrf9q6/AP" +
            "IIpTL6+Z/OjGZExDq3QB061QK6wYvw//ZqoB/t1ADzyz+n/TfH+WXmXI7DpQQCH/hufsp6S3SkM899O9Y3+4E3ifZOjOd48QXaehvyr8pXT8GlLSWEi5ZN3H9gOuAW" +
            "dfXBCSm/iVbYNbBcCkJWmLo73yN6GYYp/3lWKeySgM6BMf7/RAgMBAAECggEABGB1CkMg16o5EVw61Ci0s1n9PTSLSKjfknSpXz6orki5jMqxaJxf/v2HU87HaKPI+" +
            "Ofjg26GVV+rxkOL4fOUVu6vnYyJKFIfvU08lW/P7vNqndMIn5dpY1hEP1+b8gr6n2+yv5m2k85MYwvoZ4mdWGLHqjL1+Y2Zsk8Ng2Ui1esVdO3RiIIA626uuFonwUCG" +
            "5FuI40C6tx57uUguqMPDyUBf/TBgGlLMTi4ZJrkpqkLynjIlhRl+FXxhulMtIP+8/qHiqw8blcBACO5hnabYcHpNta+9CHu2NNQMV8qDrl16zq0HFWSNoomqG9RwZ+E" +
            "XnLyKgLfWwB2V2eMZV8kduQKBgQD8FhHA3cABNM0n+B1lIhu0Z/7PHgQFOPpbgE9n/NoGOkrKF0ZJOtuHwEgY+MOm1Xi8DnHFXkoJs47FCbBNdXeOu6mUEevOKpbBAV" +
            "sR5ir+tNfaHTCXyZUrAs8C/MnWiIpAudX9LkZeUhpXeKy4imUJ2GRK9EIRFJRbpgRvj/RjOQKBgQDYWtmLewWU8PJrVgYs5us+IyNEobP/m771312Jsvlr4hK5tEko" +
            "MbWV8rq2lbRnoxtp/RWeb7Ns5DU8kjzeYZfDSIKpSycR764CitSi8Gqtq2JN6SwKWQyTs+XvelgZztNhHJlXfMuKzPk4vG+cU5Qs7/BSGyYZ7OOhXK+6nC5JWQKBgQ" +
            "CF41LalOx9t4WfTPCP3mXIk9OKPe70tyaBosyJ9on19M/0NhhmnJQsrbudR8LiwU620xUqNsIsFOonTNYOze0KKjIPKtWLUqNvL0EnaJA9Z9+dQROmCrLnfT5l381z" +
            "3GFRr2IwbnuBbSoAe1+BREAV0pCyHrlYSQ3i/3IrrtGmQQKBgA+UIxv/BLzfyKTf8dvj2MaFozF670oVfd+YcNTMdVdGVRDYIXhqc+fTLYyeJPpdbUjpd1gMNQA/Qn" +
            "IVGZrtrg7atsXX6n1JI998/aip5RSSRabUhl5MYTJ1frYKujNJiEDy3TvGeaWJ8twZ/XNlNUMzF7vhxpGRVCa3VNP8EP0pAoGAI5jCKytf5KSlRp0ja7t0UJcN2tcO" +
            "d1x7zZYpH0j/l2zxyeVVMjsFtWbmkXm9wTcRC+mDGK+1aAhKOcTG1pEYbK2vYJf0jOL8mETRd1RWM1Q/rxa7lzBe5S4+d66NVThvatY9gcepczYRPq+NSbEcEhM9/" +
            "uEiiZ6vw110UMF06uc=";

    /**
     * LicenseUtils
     */
    private LicenseUtils() {
        // noImpl
    }

    /**
     * 验证License，验证通过返回过期时间，验证不通过返回null
     *
     * @return data
     */
    public static String checkLicense(String licenseCode) {
        // License字符串
        // 非对称key解密
        if (StringUtils.isBlank(licenseCode)) {
            return null;
        }
        String licenseJson = decodeLicense(licenseCode);
        if (StringUtils.isBlank(licenseJson)) {
            return null;
        }
        Map<String, String> licenseMap = JSON.parse(licenseJson, Map.class);
        String licenseCreateTime = licenseMap.get("createTime");
        String licenseExpireTime = licenseMap.get("expireTime");
        String licenseDeviceId = licenseMap.get("deviceId");

        // 校验
        long currTime = System.currentTimeMillis();
        if (licenseDeviceId.equals(DeviceTool.getDeviceId())
                && currTime >= Long.parseLong(licenseCreateTime)
                && currTime <= Long.parseLong(licenseExpireTime)) {
            return licenseExpireTime;
        }
        return null;
    }

    /**
     * 解密License信息
     *
     * @param licenseEncryptedBase64String 加密过的base64格式的license字符串
     * @return String
     */
    private static String decodeLicense(String licenseEncryptedBase64String) {
        try {
            byte[] encryptedBytes = Base64.getDecoder().decode(licenseEncryptedBase64String);
            // 解密
            Cipher decryptCipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
            byte[] privateKeyBytes = Base64.getDecoder().decode(PRIVATE_KEY);
            // 创建密钥规格（KeySpec）对象，这里我们使用PKCS#8编码格式
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
            // 获取KeyFactory实例
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            // 通过KeySpec从字节数组中还原PrivateKey对象
            decryptCipher.init(Cipher.DECRYPT_MODE, keyFactory.generatePrivate(pkcs8KeySpec));
            byte[] decryptedBytes = decryptCipher.doFinal(encryptedBytes);
            return new String(decryptedBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * getLicense
     *
     * @return String
     */
    public static String getLicense() {
        // 从本机idea全局配置缓存中读取
        File licFile = PathManager.getCommonDataPath().resolve(LICENSE_DIR).resolve(LICENSE_FILE).toFile();
        if (licFile.exists()) {
            return readFileToString(licFile.getPath());
        }
        return null;
    }

    /**
     * saveLicense
     *
     * @param licenseCode licenseCode
     */
    public static boolean saveLicense(String licenseCode) {
        File licFileDir = PathManager.getCommonDataPath().resolve(LICENSE_DIR).toFile();
        try {
            if (!licFileDir.exists() && !licFileDir.mkdirs()) {
                return false;
            }
            if (System.getProperty("os.name").toLowerCase().contains("win")) { // Windows 系统
                // 在 Windows 上，我们可以通过 Files.setAttribute 来设置 dos:readonly 属性
                Files.setAttribute(licFileDir.toPath(), "dos:hidden", true);
            }
            File licFile = new File(licFileDir, LICENSE_FILE);
            if (licFile.exists()) {
                Files.delete(licFile.toPath());
            }
            Files.write(licFile.toPath(), licenseCode.getBytes());
            return true;
        } catch (IOException e) {
            // ignore
        }
        return false;
    }

    /**
     * readFileToString
     *
     * @param filePath filePath
     * @return String
     */
    private static String readFileToString(String filePath) {
        try (Stream<String> lines = Files.lines(Paths.get(filePath), StandardCharsets.UTF_8)) {
            return lines.collect(Collectors.joining(System.lineSeparator()));
        } catch (IOException e) {
            return null;
        }
    }

}
